package com.tongtong.middleware.blockchain.service;

import com.tongtong.middleware.blockchain.client.web3j.WEB3JService;
import com.tongtong.middleware.blockchain.client.web3j.contract.ContractDecoder;
import com.tongtong.middleware.blockchain.client.web3j.contract.ERC721Input;
import com.tongtong.middleware.vo.response.SignTxRes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.web3j.abi.datatypes.Type;

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;

/**
 * @author wangqi
 */
@Service
@Slf4j
@RefreshScope
public class ERC721Service {
    @Autowired
    WEB3JService web3jService;
    @Value("${eth.managerAddr}")
    private String managerAddr;
    @Value("${eth.managerKey}")
    private String managerKey;
    @Value("${eth.erc721Addr}")
    private String contractAddr;
    @Autowired
    MetadataService metadataService;

    /**
     * 铸造NFT
     */
    public SignTxRes mintNFT(String to, BigInteger tokenId) {
        String input = ERC721Input.mint(to, tokenId);
        SignTxRes res;
        try {
            res = web3jService.signTx(contractAddr, input, managerKey);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String tokenUri = metadataService.metadataByTokenId(tokenId.toString());
        if (tokenUri.length() < 10) {
            log.error("ERC721Service mintNFT metadataByTokenId error");
        }
        return res;
    }
    /**
     * 获取授权
     */
    public SignTxRes approval(String account) {
        String input = ERC721Input.approval(account);
        SignTxRes res;
        try {
            res = web3jService.signTx(contractAddr, input, managerKey);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return res;
    }
    /**
     * 转移NFT
     */
    public SignTxRes transfer(String from, String to, BigInteger tokenId) {
        String input = ERC721Input.safeTransferFrom(from, to, tokenId);
        // 如果from不等于管理员，则判断是否授权给管理员，如果没授权则先授权
        if (!managerAddr.equalsIgnoreCase(from)) {
            String approvedStatus = isApprovedForAll(from, managerAddr);
            if ("0".equals(approvedStatus)) {
                approval(from);
            }
        }
        SignTxRes res;
        try {
            res = web3jService.signTx(contractAddr, input, managerKey);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return res;
    }
    /**
     * 销毁NFT
     */
    public SignTxRes burnNFT(BigInteger tokenId) {
        String input = ERC721Input.burn(tokenId);
        SignTxRes res;
        try {
            res = web3jService.signTx(contractAddr, input, managerKey);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return res;
    }
    /**
     * 查询指定用户拥有TokenID的数量
     */
    public String balanceOf(String account) {
        String input = ERC721Input.balanceOf(account);
        String res;
        try {
            // 查询合约，随便用个地址就行
            res = web3jService.call("0x0000000000000000000000000000000000000000", contractAddr, input);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<Type> decode = ContractDecoder.decode("uint256", res);
        return decode.get(0).getValue().toString();
    }
    /**
     * 查询用户是否被指定操作者授权
     */
    public String isApprovedForAll(String account, String operator) {
        String input = ERC721Input.isApprovedForAll(account, operator);
        String res;
        try {
            // 查询合约，随便用个地址就行
            res = web3jService.call("0x0000000000000000000000000000000000000000", contractAddr, input);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<Type> decode = ContractDecoder.decode("uint256", res);
        return decode.get(0).getValue().toString();
    }
    /**
     * 查询指定TokenID的TokenURI
     */
    public String tokenURI(BigInteger tokenId) {
        String input = ERC721Input.tokenURI(tokenId);
        String res;
        try {
            // 查询合约，随便用个地址就行
            res = web3jService.call("0x0000000000000000000000000000000000000000", contractAddr, input);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<Type> decode = ContractDecoder.decode("string", res);
        return decode.get(0).getValue().toString();
    }
    /**
     * 查询指定TokenID的拥有者地址
     */
    public String ownerOf(BigInteger tokenId) {
        String input = ERC721Input.ownerOf(tokenId);
        String res = null;
        try {
            // 查询合约，随便用个地址就行
            res = web3jService.call("0x0000000000000000000000000000000000000000", contractAddr, input);
        } catch (IOException ignored) {
        }
        if (res == null) {
            return null;
        } else {
            List<Type> decode = ContractDecoder.decode("address", res);
            return decode.get(0).getValue().toString();
        }
    }
}
